﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Xml;
using System.Data.SqlClient;

namespace SSRSViewer.Core
{
	public class RdlReportParameter
		: IRdlReportParameter
	{
		log4net.ILog log = log4net.LogManager.GetLogger(typeof(RdlReportParameter));

		IDbConnection _Connection { get; set; }
		object _ParameterEntryUserControl;
		RdlDataProvider _LookupProvider { get; set; }
		RdlValidValuesParser _ValidValuesParser { get; set; }
		RdlDefaultValuesParser _DefaultValuesParser { get; set; }
		string _DataType { get; set; }
		bool _MultiValue { get; set; }
		bool _AllowBlank { get; set; }


		public string Name { get; private set; }
		public string Prompt { get; private set; }
		public object ParameterEntryUserControl { get { return _ParameterEntryUserControl; } }
		public object Value
		{
			get { return (_ParameterEntryUserControl as IParameterEditor).EditValue; }
			set { (_ParameterEntryUserControl as IParameterEditor).EditValue = value; }
		}
		public DbType GetSqlType
		{
			get
			{
				if (_ParameterEntryUserControl is IMultipleValidValuesUserControl)
					return DbType.Object;
				else
					switch (_DataType)
					{
						case "Boolean":
							return DbType.Boolean;
						case "DateTime":
							return DbType.DateTime;
						case "Float":
							return DbType.Decimal;
						case "Integer":
							return DbType.Int32;
						case "String":
							return DbType.String;
						default:
							return DbType.String;
					}
			}
		}
		public Type GetClrType
		{
			get
			{
				switch (_DataType)
				{
					case "Boolean":
						return typeof(Boolean);
					case "DateTime":
						return typeof(DateTime);
					case "Float":
						return typeof(decimal);
					case "Integer":
						return typeof(int);
					case "String":
						return typeof(string);
					default:
						return typeof(string);
				}
			}
		}

		public RdlReportParameter(IDbConnection cn, XmlNode parameterNode, IList<RdlDataProvider> providers)
		{
			ParseNode(parameterNode);
			_Connection = cn;

			if (_ValidValuesParser != null)
				_LookupProvider = providers.Where(p => p.Name == _ValidValuesParser.DatasetName).SingleOrDefault();

			InitializeEditor();
		}

		void ParseNode(XmlNode parameterNode)
		{
			Name = parameterNode.Attributes["Name"].Value;
			foreach (XmlNode paramInfo in parameterNode.ChildNodes)
			{
				switch (paramInfo.Name)
				{
					case "DataType":
						_DataType = paramInfo.InnerText;
						break;
					case "Prompt":
						Prompt = paramInfo.InnerText;
						break;
					case "ValidValues":
						_ValidValuesParser = new RdlValidValuesParser(paramInfo);
						break;
					case "MultiValue":
						_MultiValue = Convert.ToBoolean(paramInfo.InnerText);
						break;
					case "AllowBlank":
						_AllowBlank = Convert.ToBoolean(paramInfo.InnerText);
						break;
					case "DefaultValue":
						_DefaultValuesParser = new RdlDefaultValuesParser(paramInfo);
						break;
				}
			}
		}
		void InitializeEditor()
		{
			if (_MultiValue)
			{
				Type editorType = null;

				if (Core.EditorsLibrary.TryGetValue(typeof(IMultipleValidValuesUserControl), out editorType))
				{
					IMultipleValidValuesUserControl control =
						Activator.CreateInstance(editorType) as IMultipleValidValuesUserControl;
					if (control != null)
					{
						control.Prompt = Prompt;
						control.ValuesParser = _ValidValuesParser;
						control.DataProvider = _LookupProvider;
						control.Connection = (SqlConnection)_Connection;
						control.EditingParameter = this;
						control.Initialize();
						_ParameterEntryUserControl = control;
					}
					else
					{
						log.Error("Could not render a multiple valid values user control.");
					}
				}
				else
				{
					if (_LookupProvider != null)
					{
						if (Core.EditorsLibrary.TryGetValue(typeof(ISingleValidValueUserControl), out editorType))
						{
							ISingleValidValueUserControl control = Activator.CreateInstance(editorType) as ISingleValidValueUserControl;
							control.Prompt = Prompt;
							control.DataProvider = _LookupProvider;
							control.Connection = (SqlConnection)_Connection;
							control.ValuesParser = _ValidValuesParser;
							control.EditingParameter = this;
							control.Initialize();
							_ParameterEntryUserControl = control;
						}
						else
						{ log.Error("Could not render a single valid values user control."); }
					}
					else
					{
						IParameterEditor editor = null;

						switch (_DataType.ToUpper())
						{
							case "BOOLEAN":
								if (!Core.EditorsLibrary.TryGetValue(typeof(IBooleanParameterUserControl), out editorType))
								{
									log.Error("Could not create a boolean editor user control.");
								}
								break;
							case "DATETIME":
								if (!Core.EditorsLibrary.TryGetValue(typeof(IDateParameterUserControl), out editorType))
								{
									log.Error("Could not create a boolean editor user control.");
								}
								break;
							case "INTEGER":
								if (!Core.EditorsLibrary.TryGetValue(typeof(IIntegerParameterUserControl), out editorType))
								{
									log.Error("Could not create a boolean editor user control.");
								}
								break;
							case "FLOAT":
								if (!Core.EditorsLibrary.TryGetValue(typeof(IFloatParameterUserControl), out editorType))
								{
									log.Error("Could not create a boolean editor user control.");
								}
								break;
							case "STRING":
								if (!Core.EditorsLibrary.TryGetValue(typeof(IStringParameterUserControl), out editorType))
								{
									log.Error("Could not create a boolean editor user control.");
								}
								break;
						}

						editor.EditingParameter = this;
						editor.Prompt = Prompt;

						_ParameterEntryUserControl = editor;
					}
				}

			}
		}
	}
}
